package server

import (
	"context"
	"fmt"
	"os"
	"os/signal"
	"runtime"
	"runtime/debug"
	"src/gcommon"

	"syscall"
	"time"

	. "src/zeus/entity"
	. "src/zeus/iserver"
	. "src/zeus/msghandler"
	. "src/zeus/timerwheel"

	"src/zeus/common"
	"src/zeus/dbservice"
	"src/zeus/iserver"
	"src/zeus/logger"
	"src/zeus/serverMgr"
	"src/zeus/threads"

	"github.com/shirou/gopsutil/cpu"
	"go.uber.org/atomic"
)

var _ IEntities = &Server{}

// Server 服务器
type Server struct {
	*SrvNet
	*ProtoType
	*Timer
	*Entities
	*MsgHandler
	// *IDFetcher
	*IDGenerater

	// *events.GlobalEvents
	srvCtrl iserver.IServerCtrl

	sGroupId uint32
	//时间偏移步长
	TimeStep time.Duration
	// 当前时间
	nowtime        atomic.Time
	ticker         *time.Ticker
	frameDeltaTime time.Duration
	startupTime    time.Time
	loopStopC      chan bool
	srvStopC       chan os.Signal
	// 服务器内部通讯令牌 Config.LoginSrvVerifyToken
	gsvt     string
	Releases []IReleaseAble

	IsRecover bool
	// 正在主动GC中
	GCRun atomic.Bool
}

func NewServer(srvType ServerType2, info *ServerBase, srvCtrl iserver.IServerCtrl) (srv *Server) {
	setRecover(info)
	srv = new(Server)
	if GetSrvInst() != nil {
		logger.Error("服务器已经存在，一个应用只能创建一个服务器实例")
		return nil
	}
	if info.SrvID > MaxServerID {
		logger.Error("serverID 超过了最大ID号,服务器最大ID为 ", MaxServerID)
		return nil
	}
	srv.SrvNet = NewSrvNetByInfo(srvType, info, srvCtrl)
	srv.ProtoType = NewProtoType()
	srv.MsgHandler = NewMsgHandler()
	srv.Timer = NewTimer()
	srv.Entities = NewEntities(true, srv.MsgHandler, srv, 5000)
	srv.IDGenerater = NewIDGenerater(info.SrvID)
	srv.srvCtrl = srvCtrl

	srv.sGroupId = info.GroupID
	srv.frameDeltaTime = time.Millisecond * time.Duration(1000/info.FPS)
	srv.startupTime = time.Now()
	srv.ticker = time.NewTicker(srv.frameDeltaTime)
	srv.loopStopC = make(chan bool, 8)
	srv.srvStopC = make(chan os.Signal, 8)
	srv.Releases = make([]iserver.IReleaseAble, 0)
	srv.IsRecover = gcommon.GetCfgInst().Config.Recover //viper.GetBool("Config.Recover")
	SetSrvInst(srv)
	srv.Timer.LoopDelayTimer(1*time.Minute, 1*time.Minute, srv.MemoryInfo)
	return
}

// RegMsgProc 注冊消息
func (srv *Server) RegEntitiesMsgProc(proc interface{}) {
	srv.RegMsgProc(proc)
}

func (srv *Server) RegRelease(r IReleaseAble) {
	srv.Releases = append(srv.Releases, r)
}

// 服务器内部通讯令牌 Config.LoginSrvVerifyToken
func (srv *Server) GetGSVT() string {
	return srv.gsvt
}
func (srv *Server) SetGSVT(vt string) {
	srv.gsvt = vt
}

// Run调用
func (srv *Server) init() error {
	if err := srv.SrvNet.init(); err != nil {
		return err
	}
	srv.Timer.Start()
	srv.RegEntitiesMsgProc(&esMsgProc{srv: srv})
	srv.SrvNet.regMsgProc(&serverMsgProc{srv: srv})
	srv.SrvNet.regMsgProc(srv.srvCtrl)
	srv.Entities.Init()
	srv.nowtime.Store(time.Now())
	return srv.srvCtrl.Init()
}

// 上层调用，也是上层重载
func (srv *Server) Init() error {
	srv.SrvNet.CheckDuplicateByDiscovery()
	srv.srvCtrl.WatchServer()
	// srv.SrvNet.WatchServer()
	//ETCD的服务信息注册
	serverMgr.GetServerMgr().Register()
	return nil
}

func (srv *Server) destroy() {
	// srv.LoadUpdater.Stop()

	srv.srvCtrl.Destroy()
	// srv.GlobalEvents.Destroy()
	// srv.Entities.Destroy()
	srv.Entities.SyncDestroy()
	srv.SrvNet.destroy()
	srv.Timer.Stop()
	srv.ticker.Stop()
	srv.Entities.Recycle()
	logger.Debug(logger.LogKey_Boot, "Server destory done")
	//logger.Flush()//have done this in main.go
}

// Close 关闭服务器
func (srv *Server) Close() {
	select {
	case srv.srvStopC <- syscall.SIGQUIT:
		// close(srv.loopStopC)
	default:
	}
}

// Run 逻辑入口
func (srv *Server) Run() {
	// rand.Seed(time.Now().UnixNano())

	if err := srv.init(); err != nil {
		panic(err)
	}
	//监听配置表文件变化

	srv.GetThreadGo().Go(srv.doLoop)

	//go srv.StartConsole()
	// if srv.Admin.GetConsolePort() != 0 {
	// 	go srv.StartHTTP()
	// }
	// srv.LoadUpdater.Start() //启动负载更新器
	signal.Notify(srv.srvStopC, syscall.SIGINT, syscall.SIGKILL, syscall.SIGTERM)
	//用windows服务来启动
	logger.Info("Program stopped by signal:", <-srv.srvStopC)

	srv.destroy()
	// if flags.GetFlagByBool("service") {
	// 	defer srv.destroy()
	// 	RunServer()

	// } else {

	// }

}

func (srv *Server) doLoop(ctx context.Context) {
	msgchan := srv.GetCallChan()
	netchan := srv.SrvNet.GetCallChan()
	if srv.GetDelayCallHandle() == nil {
		delayCallHandle := NewDelayCallHandle(5000)
		srv.SetDelayCallHandle(delayCallHandle)
	}
	checkAutoShutdownTk := time.NewTicker(10 * time.Second)
	defer checkAutoShutdownTk.Stop()
	for {
		select {
		case <-ctx.Done():
			return
		case <-msgchan:
			srv.DoMsg()
		case <-netchan:
			srv.SrvNet.DoMsg()
			srv.DoMsg()
		case <-checkAutoShutdownTk.C:
			srv.checkGrayscaleShutdownWhenNobody()
		case now := <-srv.ticker.C:
			now = now.Add(srv.TimeStep)
			srv.MainLoop(now)
			// default:
			// case ci := <-delayCallChan:
			// 	ci.Exec()
		}
	}
}

// MainLoop 主循环
func (srv *Server) MainLoop(now time.Time) {
	srv.nowtime.Store(now)
	defer func() {
		if srv.GetRecover() {
			if err := recover(); err != nil {
				logger.Errorf("Server MainLoop %v.", err)
				buf := common.StackTrace()
				common.UpPanic(common.NewPanicSrvMD(
					int(GetSrvInst().GetGroupId()),
					int(iserver.GetSrvInst().GetSrvType()),
					int(GetSrvInst().GetCurSrvInfo().ServerID),
					"",
					err,
					buf,
				))
			}
		}
	}()
	srv.Timer.OnTick(now)
	srv.SrvNet.MainLoop() //网关
	srv.srvCtrl.MainLoop()
	srv.DoMsg()
	srv.Entities.MainLoop()
	// srv.GlobalEvents.HandleEvent()
	//srv.Admin.ProcCmds() //命令行处理
	srv.GetDelayCallHandle().CallDelayExec()
}

// ConfigHTTPAdmin 配置控制台相关
func (srv *Server) ConfigHTTPAdmin(addr string, port uint64, admin string) {
	//srv.Admin.ConfigHTTPAdmin(addr, port, admin)
	// srv.SrvNet.SetConsole(port)
}

// // HandleCommand 控制台接口
// func (srv *Server) HandleCommand(c []string) *admin.CmdResp {
// 	switch c[0] {
// 	case "status":
// 		return srv.doStatusCmd(c)
// 	default:
// 		if iCmd, ok := srv.srvCtrl.(admin.IServerCommand); ok {
// 			return iCmd.HandleCommand(c)
// 		}
// 	}

// 	return nil
// }

// func (srv *Server) doStatusCmd(cmd []string) *admin.CmdResp {
// 	resp := &admin.CmdResp{}

// 	if len(cmd) == 2 {
// 		targetStatus, _ := strconv.ParseInt(cmd[1], 10, 32)
// 		// srv.SetStatus(int(targetStatus))
// 		str := fmt.Sprintf("切换服务器状态至%d", targetStatus)
// 		logger.Warn(str)
// 		resp.Result = 0
// 		resp.ResultStr = str
// 	} else {
// 		resp.Result = -1
// 		resp.ResultStr = "参数错误"
// 	}

// 	return resp
// }

// GetLoad 获取服务器负载信息, 取CPU和内存的大值
func (srv *Server) GetLoad() int {
	var c int
	// var vm int

	if loads, err := cpu.Percent(0, false); err == nil {
		if len(loads) > 0 {
			c = int(loads[0])
		}
	} else {
		logger.Error(err)
		c = 100
	}
	return c
	/*
		先只关心CPU，内存一般都是管够的
		如果内存不够的话，CPU也会高起来
	*/
	// if memorys, err := mem.VirtualMemory(); err == nil {
	// 	vm = int(memorys.UsedPercent)
	// } else {
	// 	logger.Error(err)
	// 	vm = 100
	// }

	// if c > vm {
	// 	return c
	// }

	// return vm
}

// GetGroupId 获取服务器组ID
func (srv *Server) GetGroupId() uint32 {
	return srv.sGroupId
}

// GetFrameDeltaTime 获取每帧间的间隔
func (srv *Server) GetFrameDeltaTime() time.Duration {
	return srv.frameDeltaTime
}

// GetStartupTime 获取服务器启动时间
func (srv *Server) GetStartupTime() time.Time {
	return srv.startupTime
}

// GetCurSrvInfo 获取当前服务器信息
// func (srv *Server) GetCurSrvInfo() *iserver.ServerInfo {
// 	return srv.SrvNet.GetSrvInfo(srv.GetSrvID())
// }

// IsSrvValid 服务是否可用
func (srv *Server) IsSrvValid() bool {
	return dbservice.CheckRedisStateForServer()
}

// Player保存使用的Stype
func (srv *Server) GetSaveType() uint8 {
	return srv.Type
}

// 设置 时间偏移步长
func (srv *Server) SetTimeStep(v int64) {
	srv.TimeStep += time.Duration(v) * time.Second
	logger.Infof("SetTimeStep %d now:%d time:%s", v, srv.TimeStep/time.Second, srv.GetTickTime().Add(time.Duration(v)*time.Second))
}

// 获取服务器当前时间
func (srv *Server) GetNowTime() time.Time {
	return srv.nowtime.Load()
}

type iInvalidHandler interface {
	InvalidHandle(entityID uint64)
}

// HandlerSrvInvalid 处理服务不可用
func (srv *Server) HandlerSrvInvalid(entityID uint64) {
	if iih, ok := srv.srvCtrl.(iInvalidHandler); ok {
		iih.InvalidHandle(entityID)
	}
}

// 当有服务的连接关闭的时候
func (srv *Server) ServerSessClosed(param ...interface{}) {
	logger.Debug(logger.LogKey_Boot, "Server_ServerSessClosed", param)
	sid, ok := param[0].(uint64)
	if !ok {
		return
	}
	//如果运行的时候，发现这个服务还是在的，那就不管了
	if srv.IsSessExist(sid) {
		return
	}

	/*
		有默认实现逻辑
		上层服务器需要重新实现这个逻辑
		默认的实现就是把本地的NTT对象给删了
		但是没有判断对应的SPACE或说去SPACE里面找Player
	*/
	// stype := 0
	srv.TravsalEntity(common.EntityType_Player, func(i IEntity) {
		if i.IsExistSID(sid) {
			// if stype == 0 {
			// 	//不知道这个服务器类型，现在要找一下
			// 	sli := i.GetSrvIDS()
			// 	for k := range sli {
			// 		if sli[k].SrvID == sid {
			// 			if sli[k].Stype == ServerTypeGateway {
			// 				stype = 1
			// 			} else {
			// 				stype = 2
			// 			}
			// 			break
			// 		}
			// 	}
			// }
			// if stype == 2 {
			// 	//是gateway
			// 	return
			// }
			srv.DestroyEntity(i.GetID())
			logger.Info("ServerSessClosed to user close.", sid, "user:", i.GetDBID())
		}
	})
}

// 我连接到别的服务器了
func (srv *Server) ServerSessConnect(srvID uint64, srvType uint8) {

}

func (s *Server) GetRecover() bool {
	return s.IsRecover
}

func setRecover(info *ServerBase) {
	isRecover := info.Recover
	threads.SetUtilLog(func(err interface{}) {
		buf := common.StackTrace()
		common.UpPanic(common.NewPanicSrvMD(
			int(GetSrvInst().GetGroupId()),
			int(iserver.GetSrvInst().GetSrvType()),
			int(GetSrvInst().GetCurSrvInfo().ServerID),
			"",
			err,
			buf,
		))
		if !isRecover {
			panic(fmt.Sprintf("Log: %s", buf))
		} else {
			logger.Error("Log:", err)
		}
	})
	common.OnRecover = func(err interface{}, args ...interface{}) {
		common.UpPanic(common.NewPanicSrvMD(
			int(iserver.GetSrvInst().GetGroupId()),
			int(iserver.GetSrvInst().GetSrvType()),
			int(iserver.GetSrvInst().GetCurSrvInfo().ServerID),
			"",
			err,
			args...,
		))
	}
}

func (this *Server) GCTick(...interface{}) {
	this.GetThreadGo().Go(func(ctx context.Context) {
		if this.GCRun.Load() {
			return
		}
		this.GCRun.Store(true)
		pro, ed := &runtime.MemStats{}, &runtime.MemStats{}
		runtime.ReadMemStats(pro)
		logger.Infof("GC start:[HeapAlloc:%.2fMB,HeapSys:%.2fMB,HeapIdle:%.2fMB,HeapReleased:%.2fMB]",
			float64(pro.HeapAlloc)/1000/1000,
			float64(pro.HeapSys)/1000/1000,
			float64(pro.HeapIdle)/1000/1000,
			float64(pro.HeapReleased)/1000/1000,
		)
		// 释放操作系统内存
		runtime.GC()
		// debug.FreeOSMemory()
		runtime.ReadMemStats(ed)
		logger.Infof("GC end:[HeapAlloc:%.2fMB,HeapSys:%.2fMB,HeapIdle:%.2fMB,HeapReleased:%.2fMB]",
			float64(ed.HeapAlloc)/1000/1000,
			float64(ed.HeapSys)/1000/1000,
			float64(ed.HeapIdle)/1000/1000,
			float64(ed.HeapReleased)/1000/1000,
		)
		this.GCRun.Store(false)

	})

}
func (this *Server) FreeMemoryTick(...interface{}) {
	this.GetThreadGo().Go(func(ctx context.Context) {
		if this.GCRun.Load() {
			return
		}
		this.GCRun.Store(true)
		pro, ed := &runtime.MemStats{}, &runtime.MemStats{}
		runtime.ReadMemStats(pro)
		logger.Infof("GC start:[HeapAlloc:%.2fMB,HeapSys:%.2fMB,HeapIdle:%.2fMB,HeapReleased:%.2fMB]",
			float64(pro.HeapAlloc)/1000/1000,
			float64(pro.HeapSys)/1000/1000,
			float64(pro.HeapIdle)/1000/1000,
			float64(pro.HeapReleased)/1000/1000,
		)
		// 释放操作系统内存
		// runtime.GC()
		debug.FreeOSMemory()
		runtime.ReadMemStats(ed)
		logger.Infof("GC end:[HeapAlloc:%.2fMB,HeapSys:%.2fMB,HeapIdle:%.2fMB,HeapReleased:%.2fMB]",
			float64(ed.HeapAlloc)/1000/1000,
			float64(ed.HeapSys)/1000/1000,
			float64(ed.HeapIdle)/1000/1000,
			float64(ed.HeapReleased)/1000/1000,
		)
		this.GCRun.Store(false)
	})

}

func (this *Server) MemoryInfo(...interface{}) {
	this.GetThreadGo().Go(func(ctx context.Context) {
		if this.GCRun.Load() {
			return
		}
		this.GCRun.Store(true)
		pro := &runtime.MemStats{}
		runtime.ReadMemStats(pro)
		logger.Infof("GC Info:[HeapAlloc:%.2fMB,HeapSys:%.2fMB,HeapIdle:%.2fMB,HeapReleased:%.2fMB]",
			float64(pro.HeapAlloc)/1000/1000,
			float64(pro.HeapSys)/1000/1000,
			float64(pro.HeapIdle)/1000/1000,
			float64(pro.HeapReleased)/1000/1000,
		)
		// 释放操作系统内存
		// runtime.GC()
		// debug.FreeOSMemory()
		// runtime.ReadMemStats(ed)
		// logger.Infof("GC end:[HeapAlloc:%.2fMB,HeapSys:%.2fMB,HeapIdle:%.2fMB,HeapReleased:%.2fMB]",
		// 	float64(ed.HeapAlloc)/1000/1000,
		// 	float64(ed.HeapSys)/1000/1000,
		// 	float64(ed.HeapIdle)/1000/1000,
		// 	float64(ed.HeapReleased)/1000/1000,
		// )
		this.GCRun.Store(false)

	})

}

func (srv *Server) checkGrayscaleShutdownWhenNobody() {
	if srv.ServerInfo.Status == iserver.SERVER_STATUS_FORBID {
		playerNum := 0
		var havePlayer func(entity iserver.IEntity)
		havePlayer = func(entity iserver.IEntity) {
			if space, ok := entity.(iserver.IEntities); ok {
				space.TravsalEntity(common.EntityType_Player, havePlayer)
			} else if entity.GetType() == common.EntityType_Player {
				playerNum++
				return
			}
		}
		switch srv.Type {
		case gcommon.ServerTypeLobby:
			srv.TravsalAllEntity(havePlayer)
		case gcommon.ServerTypeScene:
			srv.TravsalAllEntity(havePlayer)
		case gcommon.ServerTypeInstance:
			srv.TravsalAllEntity(havePlayer)
		case gcommon.ServerTypeGateway:
			srv.TravsalAllEntity(havePlayer)
		default:
			return
		}
		if playerNum == 0 {
			srv.Close()
		} else {
			logger.Infof("&&& 灰度下线中 当前服务器在线人数:%v,当人数为0则自动关闭本服务器", playerNum)
		}
	}
}
